package com.example.valueanimationhelper;

import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.AnimatorSet;
import android.animation.PropertyValuesHolder;
import android.animation.TypeConverter;
import android.animation.TypeEvaluator;
import android.animation.ValueAnimator;
import android.content.Context;
import android.graphics.PointF;
import android.view.animation.LinearInterpolator;

import java.util.ArrayList;

/**
 * @author COCO
 * @date 2018/11/20
 */
public class ValueAnimatorHelper {

    private Context mContext;
    private AnimationListener mListener;

    public ValueAnimatorHelper(Context mContext, AnimationListener listener) {
        this.mContext = mContext;
        this.mListener = listener;
    }

    public void playMultipleAnimations(ArrayList<ValueContainer> list) {
        AnimatorSet animatorSet = new AnimatorSet();
        animatorSet.setInterpolator(new LinearInterpolator());
        animatorSet.playTogether(createAnimatorList(list));
        animatorSet.start();
    }

    public void playSingleAnimation(ValueContainer container) {
        ValueAnimator valueAnimator = createAnimatorObject(container);
        valueAnimator.start();
    }

    private ArrayList<Animator> createAnimatorList(ArrayList<ValueContainer> list) {
        ArrayList<Animator> animatorList = new ArrayList<>();
        if (list != null && list.size() > 0) {
            for (ValueContainer valueContainer : list) {
                ValueAnimator valueAnimator = createAnimatorObject(valueContainer);
                animatorList.add(valueAnimator);
            }
        }
        return animatorList;
    }


    private ValueAnimator createAnimatorObject(final ValueContainer valueContainer) {
        final ValueAnimator valueAnimator = ValueAnimator.ofPropertyValuesHolder(valueContainer.propertyValuesHolder);
        valueAnimator.setDuration(valueContainer.duration);
        valueAnimator.setStartDelay(valueContainer.startDelay);
        valueAnimator.setInterpolator(new LinearInterpolator());
        valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                if (mListener != null) {
                    if ("TEST".equals(valueContainer.propertyName)) {
                        float animatedValue = (float) animation.getAnimatedValue(valueContainer.propertyName);
                        mListener.updateValue(animatedValue, valueContainer.propertyName);

                    } else if ("CLICK_ITEM".equals(valueContainer.propertyName)) {
                        AnimationValue animationValue
                                = (AnimationValue) animation.getAnimatedValue(valueContainer.propertyName);
                        mListener.updateAnimationValue(animationValue, valueContainer.propertyName);
                    }
                }
            }
        });
        valueAnimator.addListener(new AnimatorListenerAdapter() {
            @Override
            public void onAnimationEnd(Animator animation) {
                if (mListener != null) {
                    mListener.onAnimationEnd(valueContainer.endValue, valueContainer.propertyName);
                }
            }

            @Override
            public void onAnimationStart(Animator animation) {
                if (mListener != null) {
                    mListener.onAnimationStart(valueContainer.startValue, valueContainer.propertyName);
                }
            }
        });

        return valueAnimator;
    }

    public interface AnimationListener {
        void onAnimationStart(float value, String propertyName);

        void onAnimationEnd(float value, String propertyName);

        void updateValue(float value, String propertyName);

        void updateAnimationValue(AnimationValue animationValue, String propertyName);
    }

    public static class ValueContainer {
        int duration;
        int startDelay;
        float startValue;
        float endValue;
        String propertyName;
        PropertyValuesHolder propertyValuesHolder;

        public ValueContainer(int duration, int startDelay, String propertyName, float... values) {
            this.duration = duration;
            this.startDelay = startDelay;
            this.propertyName = propertyName;
            this.startValue = values[0];
            this.endValue = values[values.length - 1];
            this.propertyValuesHolder = createPropertyValuesHolder(values);
        }

        public ValueContainer(int duration, int startDelay, String propertyName,
                              AnimationValue startValue, AnimationValue endValue) {
            this.duration = duration;
            this.startDelay = startDelay;
            this.propertyName = propertyName;
            this.propertyValuesHolder = createPropertyValuesHolder(startValue, endValue);
        }

        private PropertyValuesHolder createPropertyValuesHolder(float... values) {
            return PropertyValuesHolder.ofFloat(propertyName, values);
        }

        private PropertyValuesHolder createPropertyValuesHolder(AnimationValue startValue,
                                                                AnimationValue endValue) {
            return PropertyValuesHolder.ofObject(propertyName, new CustomTypeEvaluator(), startValue, endValue);
        }

        private class CustomTypeEvaluator implements TypeEvaluator {
            @Override
            public Object evaluate(float fraction, Object startValue, Object endValue) {
                AnimationValue startValueObject = (AnimationValue) startValue;
                AnimationValue endValueObject = (AnimationValue) endValue;
                return new AnimationValue(
                        startValueObject.value1 + fraction * (endValueObject.value1 - startValueObject.value1),
                        startValueObject.value2 + fraction * (endValueObject.value2 - startValueObject.value2),
                        startValueObject.value3 + fraction * (endValueObject.value3 - startValueObject.value3)
                );
            }
        }
    }

    public static class AnimationValue {
        float value1;
        float value2;
        float value3;

        AnimationValue(float value1, float value2, float value3) {
            this.value1 = value1;
            this.value2 = value2;
            this.value3 = value3;
        }
    }
}
